home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1 / Nebula One.iso / Misc / RZToDoList / Source / ObjectError.m < prev    next >
Encoding:
Text File  |  1995-06-12  |  6.3 KB  |  291 lines

  1. /* 
  2.  * ObjectError
  3.  *
  4.  * You may freely copy, distribute and reuse the code in this example.
  5.  * This code is provided AS IS without warranty of any kind, expressed 
  6.  * or implied, as to its fitness for any particular use.
  7.  *
  8.  * Copyright 1995 Ralph Zazula (rzazula@next.com).  All Rights Reserved.
  9.  *
  10.  * Based on the original ObjectError by Julie Zelenski
  11.  *
  12.  */
  13.  
  14. #import "ObjectError.h"
  15. #import <appkit/nextstd.h>
  16. #import <sys/signal.h>
  17. #import <strings.h>
  18. #import <stdio.h>
  19.  
  20. typedef struct _sig {
  21.     int number;
  22.     BOOL isOn;
  23.     char *message;
  24. } SignalItem;
  25.  
  26. typedef struct _type {
  27.     char encoding;
  28.     char *format;
  29.     char *name;
  30. } ObjcType;
  31.  
  32. extern SignalItem signals[];
  33. extern ObjcType encodings[];
  34.  
  35. @implementation ObjectError
  36.  
  37. static void handle_signal (int signal);
  38. static BOOL ignoreCrashes;
  39.  
  40. + setup
  41. {
  42.     [self poseAs:[Object class]];
  43.     [self setSignalHandler:handle_signal];
  44.     ignoreCrashes = NO;
  45.     return self;
  46. }
  47.  
  48. + setSignalHandler:(void(*)())handler
  49. {
  50.     SignalItem *cur;
  51.     
  52.     for(cur = signals; cur->number; cur++) {
  53.         if(cur->isOn) {
  54.             signal(cur->number, handler);
  55.         }
  56.     }
  57.     return self;
  58. }
  59.  
  60. + resumeHandlingCrashes
  61. {
  62.     [self setSignalHandler:handle_signal];
  63.     ignoreCrashes = NO;
  64.     return self;
  65. }
  66.  
  67. + stopHandlingCrashes
  68. {
  69.     [[self class] setSignalHandler:(void (*)())SIG_DFL];
  70.     ignoreCrashes = YES;
  71.     return self;
  72. }
  73.  
  74. #define MAX_FUNCTION_ARGS 4
  75.  
  76. + printFunctionFromFP:(void *)framePointer
  77. {
  78.     char buffer[256];
  79.     char line[1024];
  80.     void *argStart;
  81.     long argNum;
  82.     
  83.     sprintf(line, "function (");
  84.     argStart = framePointer + 8;
  85.     for(argNum = 0; argNum < MAX_FUNCTION_ARGS; argNum++) {
  86.         sprintf(buffer, "%s0x%06lx", (argNum != 0 ? ", " : ""),
  87.             *(((long *)argStart) + argNum));
  88.         strcat(line, buffer);
  89.     }
  90.     strcat(line, ")");
  91.     NXLogError("%s\n",line);
  92.     return self;
  93. }
  94.  
  95. #define IS_CLASS(object) ([object class] == object)
  96.  
  97. + printMethodFromFP:(void *)framePointer
  98. {
  99.     char buffer[256];
  100.     char line[1024];
  101.     SEL selector;
  102.     id object;
  103.     Method m;
  104.     BOOL isClassMethod;
  105.         
  106.     object = *(id *)(framePointer + 8);
  107.     selector = *(SEL *)(framePointer + 12);
  108.     isClassMethod = IS_CLASS(object);
  109.     
  110.     sprintf(line, "%c[%s %s",(isClassMethod ? '+' : '-'),
  111.         object_getClassName(object), sel_getName(selector));
  112.         
  113.     m = (isClassMethod ? class_getClassMethod([object class], selector) :
  114.         class_getInstanceMethod([object class], selector));
  115.         
  116.     if(m) {
  117.         void *argStart = (framePointer + 8);
  118.         int argNum, numArgs, offset;
  119.         char *type;
  120.         
  121.         numArgs = method_getNumberOfArguments(m);
  122.         argNum = 2;
  123.         while(argNum < numArgs) {
  124.             ObjcType *cur;
  125.             
  126.             method_getArgumentInfo(m, argNum, &type, &offset);
  127.             for(cur = encodings; cur->encoding; cur++) {
  128.                 if(cur->encoding == type[0]) {
  129.                     sprintf(buffer, " :(%s)", cur->name);
  130.                     strcat(line,buffer);
  131.                     sprintf(buffer,cur->format,*(long*)(argStart+offset));
  132.                     strcat(line,buffer);
  133.                     break;
  134.                 }
  135.             }
  136.             argNum++;
  137.         }
  138.     } else {
  139.         strcat(line, "  Unknown Method");
  140.     }
  141.     strcat(line, "]");
  142.     NXLogError("%s\n",line); 
  143.     return self;
  144. }
  145.  
  146. #define MAX_FRAMES 50
  147.  
  148. + printBacktrace
  149. {
  150.     void *framePointer;
  151.     unsigned int frameCount;
  152.     
  153.     [self stopHandlingCrashes];
  154.     
  155. #if DEBUG
  156.     framePointer = ((void *) &self) - 8;
  157.     frameCount = 0;
  158.     
  159.     while(frameCount < MAX_FRAMES && framePointer) {
  160.         if(sel_isMapped(*(SEL *)(framePointer + 12))) {
  161.             [self printMethodFromFP:framePointer];
  162.         } else {
  163.             [self printFunctionFromFP:framePointer];
  164.         }
  165.         
  166.         framePointer = (void *)*(long *)framePointer;
  167.     }
  168. #endif
  169.         
  170.     return self;
  171. }
  172.  
  173. + dumpBacktrace:(const char *)message
  174. {
  175.     NXLogError("%s: %s\n", [self name], message);
  176.     [self printBacktrace];
  177.     return self;
  178. }
  179.  
  180. static void handle_signal(int signal)
  181. {
  182.     const char *msg = NULL;
  183.     char buf[256];
  184.     SignalItem *cur;
  185.     
  186.     msg = "Unrecognized signal";
  187.     for(cur = signals; cur->number; cur++) {
  188.         if(cur->number == signal) {
  189.             msg = cur->message;
  190.             break;
  191.         }
  192.     }
  193.     sprintf(buf, "Caught signal #%d: \"%s\"",signal, msg);
  194.     [ObjectError dumpBacktrace:buf];
  195. }
  196.  
  197. - error:(const char *)aString, ...;
  198. {
  199.     va_list ap;
  200.     char buffer[1024];
  201.     
  202.     va_start(ap, aString);
  203.     vsprintf(buffer, aString, ap);
  204.     va_end(ap);
  205.     if(!ignoreCrashes) {
  206.         [[self class] dumpBacktrace:buffer];
  207.         [[self class] resumeHandlingCrashes];
  208.     } else {
  209.         return [super error:buffer];
  210.     }
  211.     return self;
  212. }
  213.  
  214. + error:(const char *)aString, ...;
  215. {
  216.     va_list ap;
  217.     char buffer[1024];
  218.     
  219.     va_start(ap, aString);
  220.     vsprintf(buffer, aString, ap);
  221.     va_end(ap);
  222.     if(!ignoreCrashes) {
  223.         [[self class] dumpBacktrace:buffer];
  224.         [[self class] resumeHandlingCrashes];
  225.     } else {
  226.         return [super error:buffer];
  227.     }
  228.     return self;
  229. }
  230.  
  231. #define ON 1
  232. #define OFF 0
  233.  
  234. SignalItem signals[] = {
  235.     { SIGHUP        , OFF,    "hangup"},
  236.     { SIGINT        , OFF,    "interrupt"},
  237.     { SIGQUIT    , ON,        "quit"},
  238.     { SIGILL        , ON,        "illegal instruction"},
  239.     { SIGTRAP    , ON,        "trace trap"},
  240.     { SIGIOT        , ON,        "IOT instruction"},
  241.     { SIGEMT        , ON,        "EMT instruction"},
  242.     { SIGFPE        , ON,        "floating point exception"},
  243.     { SIGKILL    , OFF,    "kill"},
  244.     { SIGBUS        , ON,        "bus error"},
  245.     { SIGSEGV    , ON,        "segmentation violation"},
  246.     { SIGSYS        , ON,        "bad argument to system call"},
  247.     { SIGPIPE    , OFF,    "write on pipe with no reader"},
  248.     { SIGALRM    , OFF,    "alarm clock"},
  249.     { SIGTERM    , OFF,    "software termination"},
  250.     { SIGURG        , OFF,    "urgent condition present on socket"},
  251.     { SIGSTOP    , OFF,    "stop"},
  252.     { SIGTSTP    , OFF,    "stop signal generated from keyboard"},
  253.     { SIGCONT    , OFF,    "continue after stop"},
  254.     { SIGCHLD    , OFF,    "child status has changed"},
  255.     { SIGTTIN    , OFF,    "background read attempted from control terminal"},
  256.     { SIGTTOU    , OFF,    "background write attempted to control terminal"},
  257.     { SIGIO        , OFF,    "i/o is impossible on descriptor"},
  258.     { SIGXCPU    , OFF,     "cpu time limit exceeded"},
  259.     { SIGXFSZ    , OFF,    "file size limit exceeded"},
  260.     { SIGVTALRM    , OFF,    "virtual time alarm"},
  261.     { SIGPROF    , OFF,    "profiling timer alarm"},
  262.     { SIGWINCH    , OFF,    "window size changed"},
  263.     { SIGUSR1    , OFF,    "user defined #1"},
  264.     { SIGUSR2    , OFF,    "user defined #2"},
  265.     {0},
  266. };
  267.  
  268. ObjcType encodings[] = {
  269.     {  _C_ID,        "0x%06lx",     "id"},
  270.     {  _C_CLASS,    "0x%06lx",    "Class"},
  271.     {  _C_SEL,        "%s",            "SEL"},
  272.     {  _C_CHR,        "%c",            "char"},
  273.     {  _C_UCHR,        "%c",            "unsigned char"},
  274.     {  _C_SHT,        "%s",            "short"},
  275.     {  _C_USHT,        "%s",            "unsigned short"},
  276.     {  _C_INT,        "%d",            "int"},
  277.     {  _C_UINT,        "%d",            "unsigned int"},
  278.     {  _C_LNG,        "%l",            "long"},
  279.     {  _C_ULNG,        "%l",            "unsigned long"},
  280.     {  _C_FLT,        "%f",            "float"},
  281.     {  _C_DBL,        "%f",            "double"},
  282.     {  _C_VOID,        "0x%06lx",    "void"},
  283.     {  _C_PTR,        "0x%06lx",    "pointer"},
  284.     {  _C_CHARPTR,    "*s",            "char *"},
  285.     {  _C_STRUCT_B,"%x",            "struct"},
  286.     {  0,             "0x%06lx",    "Unknown"},
  287. };
  288.  
  289. @end
  290.  
  291.